package com.ts.api.module.api.convert.core.context;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.cache.local.CacheUtils;
import com.gitee.apanlh.util.reflection.ClassUtils;
import com.gitee.apanlh.util.reflection.CopyUtils;
import com.gitee.apanlh.util.reflection.ReflectionUtils;
import com.ts.api.module.api.entity.ApiUserRequest;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 *  API字段映射上下文
 *
 *  @author Pan
 */
public class ApiFieldMappingContext {

    private static final Map<String, List<ApiFieldMapping>> FIELD_MAPPING_CACHE = CacheUtils.cache(MapUtils.newHashMap());

    /**
     *  将字段解析成请求对象
     *
     *  @param  jsonString      传输对象
     *  @param  sourceObj       原始类
     *  @return ApiUserRequest
     */
    public static ApiUserRequest parseMapping(String jsonString, Object sourceObj) {
        String className = ClassUtils.getName(sourceObj);

        //  解析对象
        JSONObject jsonObject = JSONObject.parseObject(jsonString, Feature.IgnoreNotMatch);

        //  获取映射集合
        List<ApiFieldMapping> mappers = getMappers(className, sourceObj);

        //  处理转换值
        IteratorUtils.array(mappers, mapper -> mapper.apply(jsonObject, sourceObj));

        //  转换值
        return CopyUtils.copy(sourceObj, ApiUserRequest.class);
    }

    private static List<ApiFieldMapping> getMappers(String className, Object sourceObj) {
        List<ApiFieldMapping> apiFieldMappings = FIELD_MAPPING_CACHE.get(className);

        if (apiFieldMappings == null) {
           return buildMappers(className, sourceObj);
        }
        return apiFieldMappings;
    }

    private static List<ApiFieldMapping> buildMappers(String className, Object sourceObj) {
        Field[] fields = ReflectionUtils.getFields(sourceObj);
        List<ApiFieldMapping> newMapping = CollUtils.newArrayList(fields.length);

        //  添加映射实体字段
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            ApiFieldMapping apiFieldMapping = new ApiFieldMapping(field);

            //  检测是否无注解
            if (!apiFieldMapping.hasNullAnn()) {
                newMapping.add(apiFieldMapping);
            }
        }
        return FIELD_MAPPING_CACHE.put(className, newMapping);
    }
}
